#include "perspective_model.h"
#include "b_spline3.h"
#include <iostream>

const unsigned int PerspectiveModel::columnStep = 2;
const float PerspectiveModel::columnWidth 	= 0.4f;
const float PerspectiveModel::columnDepth 	= 0.4f;
const float PerspectiveModel::railWidth 	= 0.08f;
const float PerspectiveModel::railHeight 	= 0.08f;

const float PI =  3.14159265358979323846f;

PerspectiveModel::PerspectiveModel(Model& hModel,Model& tModel)
	: hModel(hModel) , tModel(tModel){
}

PerspectiveModel::~PerspectiveModel(){
}

void PerspectiveModel::calculate(){
	points.clear();

	TopModel& tmodel = dynamic_cast<TopModel&>(tModel);
	HeightModel& hmodel = dynamic_cast<HeightModel&>(hModel);

	CurveModel::Points::const_iterator tpoints = tmodel.pointsBegin();

	unsigned int hControlSize = hmodel.controlSize();
	unsigned int tControlSize = tmodel.controlSize();
	float nu =  tControlSize+1;
	float nw =  hControlSize/4;

	for(unsigned int u=0;u<tmodel.bufferSize()-1;++tpoints,++u){
		float w = (nw/nu)*((float)u/BSpline3::step);
		Point ref(-tmodel.getXRef(),-tmodel.getYRef(),-hmodel.getGroundRef());
		Point p(tpoints->x1,tpoints->x2,hmodel.calculatePoint(w).x2);
		Point final = (p+ref)*tmodel.getScale();

		this->points.push_back(final);
	}
	this->points.push_back(this->points.front());

	calculateRailPoints();
	calculateColumns();
}

void PerspectiveModel::calculateColumns(){
	unsigned int w=0;
	columns.clear();
	while(w<points.size()-1){
		Point pa=points[w];
		Point pb;

		if((w+1)<points.size()){
			pb = points[w+1];
		}else{
			pb = points[0];
		}

		Point curveDir = pb-pa;
		float xyang = atan2(curveDir.x2,curveDir.x1);

		Column col(columnWidth,(pa.x3),columnDepth,pa,xyang*180/PI);

		// Si el riel esta al raz del piso no tiene sentido una columna
		if(col.getHigh()>0){
			columns.push_back(col);
		}

		w+=(unsigned int)floor((float)(BSpline3::step/(float)columnStep)+0.5f);
	}
}

void PerspectiveModel::calculateRailPoints(){
	railPoints.clear();
	std::vector<Point>::const_iterator it = points.begin();

	// Transformo los puntos de la curva en segmentos de cubos
	for(;it!=points.end();){
		Point pa=*it;
		Point pb;

		++it;
		if(it!=points.end()){
			pb = *it;
		}else{
			pb = *points.begin();
		}

		Point curveDir = pb-pa;
		float xyang = (PI)/2+atan2(curveDir.x2,curveDir.x1);

		Point p[4] = {	Point(-railWidth/2,0,railHeight/2),
						Point(railWidth/2,0,railHeight/2),
						Point(railWidth/2,0,-railHeight/2),
						Point(-railWidth/2,0,-railHeight/2) };

		for(unsigned int c=0;c<4;c++){
			p[c].rotateXY(xyang);
			p[c] += pa;
			railPoints.push_back(p[c]);
		}
	}
}
